library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.all;


entity gle_mips is						-- to enable the 64bits extension use	
generic (NUMBIT  : integer := 32;		-- 64		
			OPSIZE  : integer := 6;			-- 20
			REGSIZE : integer := 5;			-- 6
			ROMSIZE : integer := 48;	-- and go in instruction_fetch.vhd and change the architecture of ROM
			RAMSIZE : integer := 6);
port( clock	 			: in  std_logic;
		reset	 			: in  std_logic;
		TEST_IF_opcode			: out std_logic_vector (OPSIZE-1 downto 0);
		TEST_IF_r_s 			: out std_logic_vector (REGSIZE-1 downto 0);
		TEST_IF_r_t 			: out std_logic_vector (REGSIZE-1 downto 0);
		TEST_IF_r_d 			: out std_logic_vector (REGSIZE-1 downto 0);
		TEST_IF_Imm 			: out std_logic_vector (NUMBIT/2-1 downto 0);
		TEST_IF_shamt  		: out std_logic_vector (REGSIZE-1 downto 0);
		TEST_IF_func  			: out std_logic_vector (OPSIZE-1 downto 0);
		TEST_IF_NPC_out		: out std_logic_vector (NUMBIT-1 downto 0);
--		TEST_ID_A_out			: out std_logic_vector (NUMBIT-1 downto 0);
--		TEST_ID_B_out			: out std_logic_vector (NUMBIT-1 downto 0);
--		TEST_ID_Imm_out		: out std_logic_vector (NUMBIT-1 downto 0);
--		TEST_EX_ALU_output 	: out std_logic_vector (NUMBIT-1 downto 0);
--		TEST_EX_branch 		: out std_logic;	
--		TEST_EX_status			: out std_logic;
--		TEST_MM_mux_out		: out std_logic_vector (NUMBIT-1 downto 0);
--		TEST_MM_result			: out std_logic_vector (NUMBIT-1 downto 0);
--		TEST_MM_NPC_final		: out std_logic_vector (NUMBIT-1 downto 0);
--		TEST_CU_alu_mux   	: out std_logic_vector (3 downto 0);
--		TEST_CU_info 			: out std_logic;							
--		TEST_CU_types			: out std_logic;						
--		TEST_CU_extra			: out std_logic;					
--		TEST_CU_left_mux  	: out std_logic;  						
--		TEST_CU_right_mux 	: out std_logic; 						
--		TEST_CU_cond_pilot	: out std_logic_vector (2 downto 0);	
--		TEST_CU_mem_cnt   	: out std_logic_vector (1 downto 0);	
--		TEST_CU_npc_mux   	: out std_logic;								
--		TEST_CU_w_en			: out std_logic;							
--		TEST_CU_wb_mux 		: out std_logic;							
		TEST_CU_en_if 	 		: out std_logic;
		TEST_CU_en_id 	 		: out std_logic;
		TEST_CU_en_ex 	 		: out std_logic;
		TEST_CU_en_mm 	 		: out std_logic;
		final_result	: out std_logic_vector (NUMBIT-1 downto 0)
);
end gle_mips;

architecture Structural of gle_mips is

component instruction_fetch is
generic( numBit	: integer := 32;
			opSize	: integer := 6;
			regSize	: integer := 5;
			romSize	: integer := 256);
port(	clk		: in  std_logic;
		rst		: in  std_logic;
		enb		: in  std_logic;
		en_start	: in  std_logic;
		PC_in	 	: in  std_logic_vector (numBit-1 downto 0);
		opcode 	: out std_logic_vector (opSize-1 downto 0);
		r_s 		: out std_logic_vector (regSize-1 downto 0);
		r_t 		: out std_logic_vector (regSize-1 downto 0);
		r_d 		: out std_logic_vector (regSize-1 downto 0);
		Imm 		: out std_logic_vector (numBit/2-1 downto 0);
		shamt  	: out std_logic_vector (regSize-1 downto 0);
		func  	: out std_logic_vector (opSize-1 downto 0);
		NPC_out	: out std_logic_vector (numBit-1 downto 0)
);
end component;

component instruction_decode is
generic (numBit 	: integer := 32;
			opSize	: integer := 6;
			regSize	: integer := 5);
port(	clk			: in  std_logic;
		rst			: in  std_logic;
		enb			: in  std_logic;
		Rs 			: in  std_logic_vector (regSize-1 downto 0);
		Rt 			: in  std_logic_vector (regSize-1 downto 0);
		Rd 			: in  std_logic_vector (regSize-1 downto 0);
		Imm_in		: in  std_logic_vector (numBit/2-1 downto 0);
		mem_in		: in  std_logic_vector (numBit-1 downto 0);	-- data from the WB stage
		w_en			: in  std_logic;							 	 		-- write enable from CU
		A_out			: out std_logic_vector (numBit-1 downto 0);
		B_out			: out std_logic_vector (numBit-1 downto 0);
		Imm_out		: out std_logic_vector (numBit-1 downto 0)
);
end component;

	
component execution_stage is
generic (numBit 	: integer := 32;
			shamtSize: integer := 5);
port(	clk 			: in  std_logic;
		rst 			: in  std_logic;
		enb 			: in  std_logic;
		NewPC 		: in  std_logic_vector (numBit-1 downto 0);	-- Program Counter + 4
		A_reg 		: in  std_logic_vector (numBit-1 downto 0);	-- first register from the register file
		B_reg 		: in  std_logic_vector (numBit-1 downto 0);	-- second register from the register file
		Imm_reg		: in  std_logic_vector (numBit-1 downto 0);	-- immediate register
		shamt_in		: in  std_logic_vector (shamtSize-1 downto 0);
		operation	: in  std_logic_vector (3 downto 0);			--operation to be executed	
		info_in		: in  std_logic;	
		types_in 		: in  std_logic;
		extra_in 		: in  std_logic;
		mux_l_pilot 	: in  std_logic;	
		mux_r_pilot 	: in  std_logic;	
		cmp_pilot	: in  std_logic_vector (2 downto 0);
		ALU_output 	: out std_logic_vector (numBit-1 downto 0);
		branch 		: out std_logic;										-- last program counter mux pilot
		status		: out std_logic
);
end component;

component memory_stage is
generic (numBit : integer := 32;
			ramSize: integer := 6);
port( 	clk 			: in  std_logic;
		rst 			: in  std_logic;
		enb 			: in  std_logic;
		cond		: in  std_logic; 										-- for the mux_0
		sel			: in  std_logic; 										-- for the mux_1
		mem_wr		: in  std_logic;										-- '0' read from mem, '1' write in mem
		mem_cnt		: in  std_logic_vector (1 downto 0);			-- memory control signal (ld/st 32,16,8 bits)
		B_in			: in  std_logic_vector (numBit-1 downto 0);	-- data from the register B
		ALU_in		: in  std_logic_vector (numBit-1 downto 0);	-- data from the output of the ALU
		NewPC		: in  std_logic_vector (numBit-1 downto 0);	-- data from the NPC register
		mux_out		: out std_logic_vector (numBit-1 downto 0);	-- output from the second mux
		result		: out std_logic_vector (numBit-1 downto 0);	-- output from the datamem
		NPC_final		: out std_logic_vector (numBit-1 downto 0)	-- real NPC sent to the PC
);
end component;

component write_back is
generic (numBit : integer := 32);
port(	LOAD_in	: in  std_logic_vector (numBit-1 downto 0);		-- from the datamem module	
		ALU_in 	: in  std_logic_vector (numBit-1 downto 0);		-- from the ALU module (or NPC in case of REGS[31])
		sel 	 	: in  std_logic;
		output 	: out std_logic_vector (numBit-1 downto 0)
);
end component;

component fsm is
generic( opSize  : integer := 6;
			regSize : integer := 5);
port(	clk		 : in  std_logic;
		rst		 : in  std_logic;
		opcode	 : in  std_logic_vector (opSize-1 downto 0);	-- opcode form the IR
		r_t 		 : in  std_logic_vector (regSize-1 downto 0);
		r_d 		 : in  std_logic_vector (regSize-1 downto 0);
		func		 : in  std_logic_vector (opSize-1 downto 0);	-- function from the IR
		Rd		 : out std_logic_vector (regSize-1 downto 0);-- destination register
		alu_mux	 : out std_logic_vector (3 downto 0);			-- operation sent to the ALU
		info 		 : out std_logic;										-- signed/unsigned, positive/negative, left/right
		types	 : out std_logic;										-- addition/subtraction, logical/arithmetical
		extra	 : out std_logic;										-- shift/rotate, logical-op
		left_mux 	 : out std_logic;  									-- left muxer pilot
		right_mux : out std_logic; 									-- right muxer pilot
		cond_pilot: out std_logic_vector (2 downto 0);			-- condition block pilot
		mem_cnt	 : out std_logic_vector (1 downto 0);			-- datamem module control signal
		mem_wr	 : out std_logic;										-- read or write in the datamem
		npc_mux	 : out std_logic;										-- mem mux_1 pilot
		w_en	 : out std_logic;										-- write enable for the register file
		wb_mux 	 : out std_logic;										-- writeback muxer pilot	
		en_if 	 : out std_logic;
		en_id 	 : out std_logic;
		en_ex 	 : out std_logic;
		en_mm 	 : out std_logic
);
end component;
------------------------------------------------------
--     Signal list used to connect the devices      --
signal i_opcode 		: std_logic_vector (OPSIZE-1 downto 0);		-- connects IF to ID and CU
signal i_func	 		: std_logic_vector (OPSIZE-1 downto 0);		-- connects IF to CU
signal i_alu_mux		: std_logic_vector (3 downto 0);		-- connects CU to EX
signal i_info			: std_logic;								-- connects CU to EX
signal i_types			: std_logic;								-- connects CU to EX
signal i_extra			: std_logic;								-- connects CU to EX
signal i_left_mux		: std_logic;								-- connects CU to EX
signal i_right_mux		: std_logic;								-- connects CU to EX
signal i_cond_pilot		: std_logic_vector (2 downto 0);		-- connects CU to EX
signal i_mem_cnt		: std_logic_vector (1 downto 0);		-- connects CU to MM
signal i_mem_wr		: std_logic;								-- connects CU to MM
signal i_npc_mux		: std_logic;								-- connects CU to MM
signal i_w_en			: std_logic;								-- connects CU to ID
signal i_wb_mux		: std_logic;								-- connects CU to WB
signal i_r_s			: std_logic_vector (REGSIZE-1 downto 0);		-- connects IF to ID
signal i_r_t			: std_logic_vector (REGSIZE-1 downto 0);		-- connects IF to ID and CU
signal i_r_d			: std_logic_vector (REGSIZE-1 downto 0);		-- connects IF to CU
signal i_Rd			: std_logic_vector (REGSIZE-1 downto 0);		-- connects CU to ID
signal i_Imm			: std_logic_vector (NUMBIT/2-1 downto 0);	-- connects IF to ID
signal i_shamt		: std_logic_vector (REGSIZE-1 downto 0);		-- connects IF to EX
signal i_NPC_out		: std_logic_vector (NUMBIT-1 downto 0);	-- connects IF to EX and MM
signal i_A_out			: std_logic_vector (NUMBIT-1 downto 0);	-- connects ID to EX
signal i_B_out			: std_logic_vector (NUMBIT-1 downto 0);	-- connects ID to EX and MM
signal i_Imm_out		: std_logic_vector (NUMBIT-1 downto 0);	-- connects ID to EX
signal i_ALU_output	: std_logic_vector (NUMBIT-1 downto 0);	-- connects EX to MM
signal i_branch		: std_logic;								-- connects EX to MM
signal i_status		: std_logic;								-- connects EX to ?
signal i_result			: std_logic_vector (NUMBIT-1 downto 0);	-- connects MM to WB
signal i_mux_out		: std_logic_vector (NUMBIT-1 downto 0);	-- connects MM to WB
signal i_NPC_final		: std_logic_vector (NUMBIT-1 downto 0);	-- connects MM to IF
signal i_output		: std_logic_vector (NUMBIT-1 downto 0);	-- connects WB to ID

--		 Signal list used for enabling registers  	 --
signal en_pc		: std_logic;
signal i_en_if 		: std_logic;
signal i_en_id 	: std_logic;
signal i_en_ex	: std_logic;
signal i_en_mm 	: std_logic;
------------------------------------------------------
begin

en_pc <= '1';

CU: fsm generic 
map ( 	opSize 	=> OPSIZE,
		regSize	=> REGSIZE) port
map (	clk			=> clock,
		rst			=> reset,
		opcode		=> i_opcode,
		r_t			=> i_r_t,
		r_d			=> i_r_d,
		func			=> i_func,
		alu_mux  	=> i_alu_mux,
		Rd			=> i_Rd,
		info 			=> i_info,
		types		=> i_types,
		extra		=> i_extra,
		left_mux 		=> i_left_mux,
		right_mux	=> i_right_mux,
		cond_pilot	=> i_cond_pilot,
		mem_cnt   	=> i_mem_cnt,
		mem_wr		=> i_mem_wr,
		npc_mux  	=> i_npc_mux,
		w_en		=> i_w_en,
		wb_mux 	 	=> i_wb_mux,
		en_if 	 	=> i_en_if,
		en_id 	 	=> i_en_id,
		en_ex 	 	=> i_en_ex,
		en_mm 	 	=> i_en_mm
);

IFs: instruction_fetch generic
map ( numBit	=> NUMBIT,
		opSize	=> OPSIZE,
		regSize	=> REGSIZE,
		romSize	=> ROMSIZE) port
map (	clk			=> clock,
		rst			=> reset,
		enb			=> i_en_if,
		en_start		=> en_pc,
		PC_in	 		=> i_NPC_final,
		opcode 		=> i_opcode,
		r_s 			=> i_r_s,
		r_t 			=> i_r_t,
		r_d 			=> i_r_d,
		Imm 			=> i_Imm,
		shamt  		=> i_shamt,
		func  		=> i_func,
		NPC_out		=> i_NPC_out
);

ID: instruction_decode generic 
map (	numBit 	=> NUMBIT,
		opSize	=> OPSIZE,
		regSize	=> REGSIZE) port
map (	clk			=> clock,
		rst			=> reset,
		enb			=> i_en_id,
		Rs 			=> i_r_s,
		Rt 			=> i_r_t,
		Rd 			=> i_Rd,
		Imm_in		=> i_Imm,
		mem_in		=> i_output,
		w_en		=> i_w_en,
		A_out		=> i_A_out,
		B_out		=> i_B_out,
		Imm_out		=> i_Imm_out
);

EX: execution_stage generic 
map (	numBit	=> NUMBIT,
		shamtSize=> REGSIZE) port
map ( clk 			=> clock,
		rst 			=> reset,
		enb 			=> i_en_ex,
		NewPC 		=> i_NPC_out,
		A_reg 		=> i_A_out,
		B_reg 		=> i_B_out,
		Imm_reg		=> i_Imm_out,
		shamt_in		=> i_shamt,
		operation	=> i_alu_mux,
		info_in		=> i_info,
		types_in 		=> i_types,
		extra_in 		=> i_extra,
		mux_l_pilot 	=> i_left_mux,
		mux_r_pilot 	=> i_right_mux,
		cmp_pilot	=> i_cond_pilot,
		ALU_output 	=> i_ALU_output,
		branch 		=> i_branch,
		status		=> i_status
);

MM: memory_stage generic 
map (	numBit 	=> NUMBIT,
		ramSize	=> RAMSIZE) port
map ( clk 			=> clock,
		rst 			=> reset,
		enb 			=> i_en_mm,
		cond		=> i_branch,
		sel			=> i_npc_mux,
		mem_wr		=> i_mem_wr,
		mem_cnt		=> i_mem_cnt,
		B_in			=> i_B_out,
		ALU_in		=> i_ALU_output,
		NewPC		=> i_NPC_out,
		mux_out		=> i_mux_out,
		result		=> i_result,
		NPC_final		=> i_NPC_final
);

WB: write_back generic 
map ( numBit 	=> NUMBIT) port
map (	LOAD_in		=> i_result,
		ALU_in 		=> i_mux_out,
		sel 	 		=> i_wb_mux,
		output 		=> i_output
);

-- begin test signals assignment --
--TEST_IF_opcode			<= i_opcode;
--TEST_IF_r_s 			<= i_r_s;
--TEST_IF_r_t 			<= i_r_t;
--TEST_IF_r_d 			<= i_r_d;
--TEST_IF_Imm 			<= i_Imm;
--TEST_IF_shamt  		<= i_shamt;
--TEST_IF_func  			<= i_func;
--TEST_IF_NPC_out		<= i_NPC_out;
--TEST_ID_A_out			<= i_A_out;
--TEST_ID_B_out			<= i_B_out;
--TEST_ID_Imm_out		<= i_Imm_out;
--TEST_EX_ALU_output 	<= i_ALU_output;
--TEST_EX_branch 		<= i_branch;
--TEST_EX_status			<= i_status;
--TEST_MM_mux_out		<= i_mux_out;
--TEST_MM_result			<= i_result;
--TEST_MM_NPC_final		<= i_NPC_final;
--TEST_CU_alu_mux   	<= i_alu_mux;
--TEST_CU_info 			<= i_info;
--TEST_CU_types			<= i_types;
--TEST_CU_extra			<= i_extra;
--TEST_CU_left_mux  	<= i_left_mux;
--TEST_CU_right_mux 	<= i_right_mux;
--TEST_CU_cond_pilot	<= i_cond_pilot;
--TEST_CU_mem_cnt   	<= i_mem_cnt;
--TEST_CU_npc_mux   	<= i_npc_mux;
--TEST_CU_w_en			<= i_w_en;
--TEST_CU_wb_mux 		<= i_wb_mux;
TEST_CU_en_if 	 		<= i_en_if;
TEST_CU_en_id 	 		<= i_en_id;
TEST_CU_en_ex 	 		<= i_en_ex;
TEST_CU_en_mm 	 		<= i_en_mm;
-- end test signals assignment --

final_result 			<= i_output;
end Structural;
--
--configuration CFG_MIPS32 of final_mips is
--	for final
--		for IFs : instruction_fetch
--			use configuration WORK.CFG_IF_32;
--		end for;
--	end for;
--end CFG_MIPS32;
--
--configuration CFG_MIPS64 of final_mips is
--	for final
--		for IFs : instruction_fetch
--			use configuration WORK.CFG_IF_64;
--		end for;
--	end for;
--end CFG_MIPS64;